package com.example.xianji.utils;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.util.Log;
import android.util.TypedValue;

/**
* Bitmap解码转换工具
*/
public class BitmapDecodeUtil {
	private static final int DEFAULT_DENSITY = 240;
	private static final float SCALE_FACTOR = 0.75f;
	private static final Bitmap.Config DEFAULT_BITMAP_CONFIG = Bitmap.Config.RGB_565;

	/**
	 * 获取优化的BitmapFactory.Options
	 * 
	 * @param context
	 * @return
	 */
	private static BitmapFactory.Options getBitmapOptions(Context context) {
		BitmapFactory.Options options = new BitmapFactory.Options();
		options.inScaled = true;// 是否支持缩放，默认为true，
		options.inPreferredConfig = DEFAULT_BITMAP_CONFIG;// Bitmap.Config.ARGB_8888等
		options.inPurgeable = true;// 当存储Pixel的内存空间在系统内存不足时是否可以被回收
		options.inInputShareable = true;// inPurgeable为true情况下才生效，是否可以共享一个InputStream
		options.inJustDecodeBounds = false;// 为true仅返回Bitmap的宽高等属性
		if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) {
			Field field = null;
			try {
				field = BitmapFactory.Options.class
						.getDeclaredField("inNativeAlloc");
				field.setAccessible(true);
				field.setBoolean(options, true);
			} catch (NoSuchFieldException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
		int displayDensityDpi = context.getResources().getDisplayMetrics().densityDpi;// 表示屏幕的像素密度
		float displayDensity = context.getResources().getDisplayMetrics().density;// 1dp等于多少个像素(px)
		if (displayDensityDpi > DEFAULT_DENSITY && displayDensity > 1.5f) {
			int density = (int) (displayDensityDpi * SCALE_FACTOR);
			options.inDensity = density;// Bitmap的像素密度
			options.inTargetDensity = density;// Bitmap最终的像素密度
		}
		return options;
	}

	/**
	 * 通过资源ID解码Bitmap
	 * 
	 * @param context
	 * @param resId
	 * @return
	 */
	public static Bitmap decodeBitmap(Context context, int resId) {
		checkParam(context);
		return BitmapFactory.decodeResource(context.getResources(), resId,
				getBitmapOptions(context));
	}

	/**
	 * 通过资源路径解码Bitmap
	 * 
	 * @param context
	 * @param pathName
	 * @return
	 */
	public static Bitmap decodeBitmap(Context context, String pathName) {
		checkParam(context);
		return BitmapFactory.decodeFile(pathName, getBitmapOptions(context));
	}

	/**
	 * 通过资源输入流解码Bitmap
	 * 
	 * @param context
	 * @param is
	 * @return
	 */
	public static Bitmap decodeBitmap(Context context, InputStream is) {
		checkParam(context);
		checkParam(is);
		return BitmapFactory.decodeStream(is, null, getBitmapOptions(context));
	}

	/**
	 * 通过资源ID获取压缩Bitmap
	 * 
	 * @param context
	 * @param resId
	 * @param maxWidth
	 * @param maxHeight
	 * @return
	 */
	public static Bitmap compressBitmap(Context context, int resId,
			int maxWidth, int maxHeight) {
		checkParam(context);
		final TypedValue value = new TypedValue();
		FileInputStream is = null;
		try {
			is = (FileInputStream) context.getResources().openRawResource(
					resId, value);
			return compressBitmap(context, is, maxWidth, maxHeight);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (is != null) {
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return null;
	}

	/**
	 * 通过资源路径获取压缩Bitmap
	 * 
	 * @param context
	 * @param pathName
	 * @param maxWidth
	 * @param maxHeight
	 * @return
	 * @throws IOException
	 */
	public static Bitmap compressBitmap(Context context, String pathName,
			int maxWidth, int maxHeight) throws IOException {
		checkParam(context);
		FileInputStream is = null;
		try {
			is = new FileInputStream(pathName);
			return compressBitmap(context, is, maxWidth, maxHeight);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} finally {
			if (is != null) {
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return null;
	}

	/**
	 * 通过资源流获取压缩Bitmap
	 * 
	 * @param context
	 * @param is
	 * @param maxWidth
	 * @param maxHeight
	 * @return
	 * @throws IOException
	 */
	public static Bitmap compressBitmap(Context context, FileInputStream is,
			int maxWidth, int maxHeight) throws IOException {
		checkParam(context);
		checkParam(is);
		BitmapFactory.Options opt = new BitmapFactory.Options();
		opt.inJustDecodeBounds = true;
		/***************
		 * decodeStream调用了两次 ,decodeStream的BUG*
		 * 首先是如何重现这种问题，很显然为了得到图片的分辨率，一般都会先把inJustDecodeBounds设置为true
		 * ，解析图片，这时候的decodeStream是必定返回null， 一般用decodeFile 
		 ************************************************/
		Bitmap bimap = BitmapFactory
				.decodeFileDescriptor(is.getFD(), null, opt);

		int height = opt.outHeight;
		int width = opt.outWidth;

		int sampleSize = computeSampleSize(width, height, maxWidth, maxHeight);

		BitmapFactory.Options options = getBitmapOptions(context);
		options.inSampleSize = sampleSize;
		/***************
		 * decodeStream调用了两次 ,decodeStream的BUG*
		 * 首先是如何重现这种问题，很显然为了得到图片的分辨率，一般都会先把inJustDecodeBounds设置为true
		 * ，解析图片，这时候的decodeStream是必定返回null，
		 ************************************************/
		Bitmap bimap1 = BitmapFactory.decodeStream(is, null, options);
		Log.i("bbbbbbbbbbbbbbbbb", height + "hhhhh:" + width
				+ "sampleSizesampleSize" + sampleSize + bimap1);
		return bimap1;
	}

	/**
	 * 计算SampleSize
	 * 
	 * @param width
	 * @param height
	 * @param maxWidth
	 * @param maxHeight
	 * @return
	 */
	private static int computeSampleSize(int width, int height, int maxWidth,
			int maxHeight) {
		int inSampleSize = 1;
		if (height > maxHeight || width > maxWidth) {
			final int heightRate = Math.round((float) height
					/ (float) maxHeight);
			final int widthRate = Math.round((float) width / (float) maxWidth);
			inSampleSize = heightRate < widthRate ? heightRate : widthRate;
		}
		if (inSampleSize % 2 != 0) {
			inSampleSize -= 1;
		}
		return inSampleSize <= 1 ? 1 : inSampleSize;
	}

	/**
	 * 检查对象是否为空
	 * 
	 * @param param
	 */
	private static void checkParam(Object param) {
		if (param == null)
			throw new NullPointerException();
	}
}
